home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 3: Developer Tools / Linux Cubed Series 3 - Developer Tools.iso / utils / file / managers / mc-3.2 / mc-3 / mc-3.2.1 / src / command.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-05-17  |  7.4 KB  |  275 lines

  1. /* Command line widget.
  2.    Copyright (C) 1995 Miguel de Icaza
  3.  
  4.    This program is free software; you can redistribute it and/or modify
  5.    it under the terms of the GNU General Public License as published by
  6.    the Free Software Foundation; either version 2 of the License, or
  7.    (at your option) any later version.
  8.  
  9.    This program is distributed in the hope that it will be useful,
  10.    but WITHOUT ANY WARRANTY; without even the implied warranty of
  11.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12.    GNU General Public License for more details.
  13.  
  14.    You should have received a copy of the GNU General Public License
  15.    along with this program; if not, write to the Free Software
  16.    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  17.  
  18.    This widget is derived from the WInput widget, it's used to cope
  19.    with all the magic of the command input line, we depend on some
  20.    help from the program's callback.
  21.  
  22. */
  23.  
  24. #include <config.h>
  25. #include <errno.h>
  26. #include "tty.h"
  27. #include "fs.h"
  28. #include <malloc.h>
  29. #include <string.h>
  30. #include <stdlib.h>
  31. #include "mad.h"
  32. #include "dlg.h"
  33. #include "widget.h"
  34. #include "command.h"
  35. #include "complete.h"        /* completion constants */
  36. #include "global.h"        /* home_dir */
  37. #include "dialog.h"        /* message () */
  38. #include "dir.h"        /* required by panel.h */
  39. #include "panel.h"        /* view_tree enum. Also, needed by main.h */
  40. #include "main.h"        /* do_cd */
  41. #include "layout.h"        /* for command_prompt variable */
  42. #include "user.h"        /* expand_format */
  43. #include "subshell.h"
  44. #include "tree.h"        /* for tree_chdir */
  45. #include "color.h"
  46. #include "../vfs/vfs.h"
  47.  
  48. /* This holds the command line */
  49. WCommand *cmdline;
  50.  
  51. /*Tries variable substitution, and if a variable CDPATH
  52. of the form e.g. CDPATH=".:~:/usr" exists, we try then all the paths which
  53. are mentioned there. Also, we do not support such extraordinary things as
  54. ${var:-value}, etc. Use the eval cd 'path' command instead.
  55. Bugs: No quoting occurrs here, so ${VAR} and $VAR will be always
  56. substituted. I think we can encourage users to use in such extreme
  57. cases instead of >cd path< command a >eval cd 'path'< command, which works
  58. as they might expect :) 
  59. FIXME: Perhaps we should do wildcard matching as well? */
  60. static int examine_cd (char *path)
  61. {
  62.     char *p;
  63.     int result;
  64.     char *q = xmalloc (MC_MAXPATHLEN + 10, "examine_cd"), *r, *s, *t, c;
  65.  
  66.     /* Variable expansion */
  67.     for (p = path, r = q; *p && r < q + MC_MAXPATHLEN; ) {
  68.         if (*p != '$' || (p [1] == '[' || p [1] == '('))
  69.             *(r++)=*(p++);
  70.         else {
  71.             p++;
  72.             if (*p == '{') {
  73.                 p++;
  74.                 s = strchr (p, '}');
  75.             } else
  76.                 s = NULL;
  77.             if (s == NULL)
  78.                 s = strchr (p, PATH_SEP);
  79.             if (s == NULL)
  80.                 s = strchr (p, 0);
  81.             c = *s;
  82.             *s = 0;
  83.             t = getenv (p);
  84.             *s = c;
  85.             if (t == NULL) {
  86.                 *(r++) = '$';
  87.                 if (*(p - 1) != '$')
  88.                     *(r++) = '{';
  89.             } else {
  90.                 if (r + strlen (t) < q + MC_MAXPATHLEN) {
  91.                     strcpy (r, t);
  92.                     r = strchr (r, 0);
  93.                 }
  94.                 if (*s == '}')
  95.                     p = s + 1;
  96.                 else
  97.                     p = s;
  98.             }
  99.         }
  100.     }
  101.     *r = 0;
  102.     
  103.     result = do_cd (q);
  104.  
  105.     /* CDPATH handling */
  106.     if (*q != PATH_SEP && !result) {
  107.         p = getenv ("CDPATH");
  108.         if (p == NULL)
  109.             c = 0;
  110.         else
  111.             c = ':';
  112.         while (!result && c == ':') {
  113.             s = strchr (p, ':');
  114.             if (s == NULL)
  115.                 s = strchr (p, 0);
  116.             c = *s;
  117.             *s = 0;
  118.             if (*p) {
  119.                 if (*(s - 1) == PATH_SEP)
  120.                     r = copy_strings (p, q, NULL);
  121.                 else
  122.                     r = copy_strings (p, PATH_SEP_STR, q, NULL);
  123.                 result = do_cd (r);
  124.                 free (r);
  125.             }
  126.             *s = c;
  127.             p = s + 1;
  128.         }
  129.     }
  130.     free (q);
  131.     return result;
  132. }
  133.  
  134. /* Execute the cd command on the command line */
  135. void do_cd_command (char *cmd)
  136. {
  137.     int len;
  138.  
  139.     /* Any final whitespace should be removed here
  140.        (to see why, try "cd fred "). */
  141.     /* NOTE: I think we should not remove the extra space,
  142.        that way, we can cd into hidden directories */
  143.     len = strlen (cmd) - 1;
  144.     while (len >= 0 &&
  145.        (cmd [len] == ' ' || cmd [len] == '\t' || cmd [len] == '\n')){
  146.     cmd [len] = 0;
  147.     len --;
  148.     }
  149.     
  150.     if (cmd [2] == 0)
  151.     cmd = "cd ";
  152.  
  153.     if (get_current_type () == view_tree){
  154.     if (cmd [0] == 0){
  155.         tree_chdir (the_tree, home_dir);
  156.     } else if (strcmp (cmd+3, "..") == 0){
  157.         char *dir = cpanel->cwd;
  158.         int len = strlen (dir);
  159.         while (len && dir [--len] != PATH_SEP);
  160.         dir [len] = 0;
  161.         if (len)
  162.         tree_chdir (the_tree, dir);
  163.         else
  164.         tree_chdir (the_tree, PATH_SEP_STR);
  165.     } else if (cmd [3] == PATH_SEP){
  166.         tree_chdir (the_tree, cmd+3);
  167.     } else {
  168.         char *old = cpanel->cwd;
  169.         char *new;
  170.         new = copy_strings (old, PATH_SEP_STR, cmd+3, 0);
  171.         tree_chdir (the_tree, new);
  172.         free (new);
  173.     }
  174.     } else
  175.     if (!examine_cd (&cmd [3])) {
  176.         message (1, " Error ", " Can't chdir to '%s' \n %s ",
  177.              &cmd [3], unix_error_string (errno));
  178.         return;
  179.     }
  180. }
  181.  
  182. /* Returns 1 if the we could handle the enter, 0 if not */
  183. static int enter (WCommand *cmdline)
  184. {
  185.     Dlg_head *old_dlg;
  186.     
  187.     if (command_prompt && strlen (input_w (cmdline)->buffer)){
  188.     char *cmd;
  189.  
  190.     /* Any initial whitespace should be removed at this point */
  191.     cmd = input_w (cmdline)->buffer;
  192.     while (*cmd == ' ' || *cmd == '\t' || *cmd == '\n')
  193.         cmd++;
  194.  
  195.     if (strncmp (cmd, "cd ", 3) == 0 || strcmp (cmd, "cd") == 0){
  196.         do_cd_command (cmd);
  197.         new_input (input_w (cmdline));
  198.         return MSG_HANDLED;
  199.     } else {
  200.         char *command, *s;
  201.         int i, j;
  202.  
  203.         if (!vfs_current_is_local ())
  204.         return MSG_NOT_HANDLED;
  205.         command = xmalloc (strlen (cmd) + 1, "main, enter");
  206.         command [0] = 0;
  207.         for (i = j = 0; i < strlen (cmd); i ++){
  208.         if (cmd [i] == '%'){
  209.             i ++;
  210.             s = expand_format (cmd [i]);
  211.             command = realloc (command, strlen (command) + strlen (s)
  212.                        + strlen (cmd) - i + 1);
  213.             strcat (command, s);
  214.             free (s);
  215.             j = strlen (command);
  216.         } else {
  217.             command [j] = cmd [i];
  218.             j ++;
  219.         }
  220.         command [j] = 0;
  221.         }
  222.         old_dlg = current_dlg;
  223.         current_dlg = 0;
  224.         new_input (input_w (cmdline));
  225.         execute (command);
  226.         free (command);
  227.         
  228. #ifdef HAVE_SUBSHELL_SUPPORT
  229.         if (quit == SUBSHELL_EXIT){
  230.             quiet_quit_cmd ();
  231.         return MSG_HANDLED;
  232.         }
  233.         if (use_subshell)
  234.         load_prompt (0, 0);
  235. #endif
  236.  
  237.         current_dlg = old_dlg;
  238.     }
  239.     }
  240.     return MSG_HANDLED;
  241. }
  242.  
  243. static int command_callback (Dlg_head *h, WCommand *cmd, int msg, int par)
  244. {
  245.     switch (msg){
  246.     case WIDGET_FOCUS:
  247.     /* We refuse the focus always: needed not to unselect the panel */
  248.     return MSG_NOT_HANDLED;
  249.  
  250.     case WIDGET_KEY:
  251.     /* Special case: we handle the enter key */
  252.     if (par == '\n'){
  253.         return enter (cmd);
  254.     }
  255.     }
  256.     return (*cmd->old_callback)(h, cmd, msg, par);
  257. }
  258.  
  259. WCommand *command_new (int y, int x, int cols)
  260. {
  261.     WCommand *cmd = xmalloc (sizeof (WCommand), "command_new");
  262.  
  263.     cmd->input = *input_new (y, x, DEFAULT_COLOR, cols, "");
  264.  
  265.     /* Add our hooks */
  266.     cmd->old_callback = (callback_fn) cmd->input.widget.callback;
  267.     cmd->input.widget.callback = (int (*) (Dlg_head *, void *, int, int))
  268.                 command_callback;
  269.     
  270.     cmd->input.completion_flags |= INPUT_COMPLETE_COMMANDS;
  271.     return cmd;
  272. }
  273.  
  274.  
  275.